package com.googlecode.jawb.clues;

import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.googlecode.jawb.BinaryType;
import com.googlecode.jawb.clues.types.DynamicLengthType;
import com.googlecode.jawb.clues.types.StaticLengthType;

/**
 * <p>Defines how a given field should be saved to (or loaded from) a binary form.
 * Fields which are not tagged with this annotation will be ignored.</p>
 * 
 * <p>Values {@link #staticLengthType()} and {@link #dynamicLengthType()} are
 * optional. If you need to use a type, which is not supported by this library,
 * you can define your own. There are two types: static-length type (it is,
 * always takes constant amount of bytes from input stream) and dynamic-length
 * type (it is, takes variable amount of bytes from input stream). To write your
 * own converter, you need to create a class which implements interface
 * {@link StaticLengthType} or {@link DynamicLengthType}. Such a class can be
 * later passed to values {@link #staticLengthType()} or
 * {@link #dynamicLengthType()} we talked before.</p>
 * 
 * <p><b>Remember: </b>{@link #staticLengthType()} or {@link #dynamicLengthType()}
 * will be only used if {@link #type()} returns value {@link BinaryType#OBJECT}!</p>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SetType {
	/**
	 * Annotations cannot have assigned "null" as a default value. Therefore,
	 * instead of "null", this class is used. All methods throws
	 * {@link UnsupportedOperationException} and constructor is marked as
	 * private to prevent instantiation.
	 */
	public class DefaultClass implements StaticLengthType, DynamicLengthType {
		private DefaultClass() {
			// prevent instantiation (this class is only a hack)
		}
		
		@Override
		public Object fromByteArray(byte[] rawBytes) {
			throw new UnsupportedOperationException();
		}

		@Override
		public int getAcceptedLength() {
			throw new UnsupportedOperationException();
		}

		@Override
		public byte[] toByteArray(Object object) {
			throw new UnsupportedOperationException();
		}

		@Override
		public Object fromByteArray(InputStream inputStream) {
			throw new UnsupportedOperationException();
		}
	};
	
	BinaryType                          type();
	Class<? extends StaticLengthType>   staticLengthType()  default DefaultClass.class;
	Class<? extends DynamicLengthType>  dynamicLengthType() default DefaultClass.class;
}
